import { request } from '@kit.BasicServicesKit';
import { fileIo } from '@kit.CoreFileKit';
import L from './L';
import { uniformTypeDescriptor, ValueType } from '@kit.ArkData';
import { Context } from '@kit.AbilityKit';
import resourceManager from '@ohos.resourceManager';


export type ValuesItemFile = {
  [key: string]: string | number | boolean;
};

/**
 * 上传帮助类
 */
export class UploadFileHelper {
  static async upload(context: Context, url: string, filePath: string,
    params: ValuesItemFile | undefined = undefined): Promise<boolean> {
    if (!fileIo.accessSync(filePath)) {
      return false;
    }
    let fileName = UploadFileHelper.getFileName(filePath);
    let mimType = UploadFileHelper.getMimType(fileName);
    let pushList: Array<request.agent.FormItem> = [];
    pushList.push({
      name: "file",
      value: {
        path: filePath,
        filename: fileName,
        mimeType: mimType
      },
    })

    if (params) {
      let keys = Object.keys(params);
      if (keys && keys.length > 0) {
        keys.forEach((key: string) => {
          let value = params[key];
          pushList.push({ name: key, value: value.toString() })
        })
      }
    }
    L.d("UploadFileHelper", "pushList:%{public}s", JSON.stringify(pushList));
    let task: request.agent.Task | null | undefined;
    try {
      task = await request.agent.create(context, {
        action: request.agent.Action.UPLOAD, //任务操作选项
        url: url, //上传地址
        title: "上传文件测试", //任务标题，其最大长度为256个字符，默认值为小写的 upload 或 download
        description: "本次测试上传文件", //任务的详细信息
        mode: request.agent.Mode.FOREGROUND, //任务模式,默认为后台任务。
        overwrite: false, //下载过程中路径已存在时的解决方案选择
        method: "POST", //上传或下载的HTTP标准方法，包括GET、POST和PUT，不区分大小写。
        // headers : {
        //   "Content-Type" : "multipart/form-data",
        //   "upload_desc" : "测试信息"
        // }, //头部信息
        data: pushList, //上传表单项数组Array<FormItem>
        saveas: undefined, //保存下载文件的路径
        network: request.agent.Network.ANY, //网络选项，当前支持无线网络WIFI和蜂窝数据网络
        metered: true, //是否允许在按流量计费的网络中工作
        roaming: true, //是否允许在漫游网络中工作
        retry: false, //是否为后台任务启用自动重试
        redirect: false, //是否允许重定向
        gauge: false, //后台任务的过程进度通知策略，仅应用于后台任务
        precise: true, //如果设置为true，在上传/下载无法获取文件大小时任务失败。
        priority: 0, //任务的优先级
        extras: {
          //附加功能
          "test": "demo"
        }
      });
      L.d("UploadFileHelper", "准备开始请求:%{public}s", JSON.stringify(task.tid));
      await task.start()
      L.d("UploadFileHelper", "发送完成");
      return true;
    } catch (e) {
      L.e("UploadFileHelper", "e:%{public}s", JSON.stringify(e));
      return false;
    } finally {
      if (task) {
        request.agent.remove(task.tid);
      }
    }
  }

  private static getFileName(filePath: string): string {
    let lastIndex = filePath.lastIndexOf("/");
    return lastIndex === -1 ? filePath : filePath.substring(lastIndex + 1);
  }

  private static getMimType(fileName: string): string {
    L.d("UploadFileHelper", "当前文件的名称为:%{public}s", JSON.stringify(fileName));
    let lastNameIndex = fileName.lastIndexOf(".");
    if (lastNameIndex === -1) {
      return "";
    }
    let fileExtention = fileName.substring(lastNameIndex + 1);
    L.d("UploadFileHelper", "当前文件的扩展名为:%{public}s", JSON.stringify(fileExtention));
    let typeId = uniformTypeDescriptor.getUniformDataTypeByFilenameExtension("." + fileExtention);
    // 3.根据UTD数据类型查询对应的MIMEType列表。
    let typeObj = uniformTypeDescriptor.getTypeDescriptor(typeId);
    let mimeTypes = typeObj.mimeTypes;
    L.d("UploadFileHelper", "当前文件的mimeTypes:%{public}s", JSON.stringify(mimeTypes));
    if (!mimeTypes || mimeTypes.length === 0) {
      return fileExtention;
    }
    return mimeTypes[0];
  }

  public static async rawFileToLocal(context: Context, assesFilePath: string, localFilePath: string): Promise<boolean> {
    let localFile: fileIo.File | null | undefined;
    let rawFile: resourceManager.RawFileDescriptor | null | undefined;
    L.d("rawFileToLocal", "资源文件地址:%{public}s", assesFilePath);
    L.d("rawFileToLocal", "本地文件存储地址:%{public}s", localFilePath);
    try {
      localFile = fileIo.openSync(localFilePath, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);
      if (!localFile) {
        return false;
      }
      rawFile = context.resourceManager.getRawFdSync(assesFilePath);
      if (!rawFile) {
        return false;
      }
      let totalLength = rawFile.length;
      L.d("rawFileToLocal", "文件总长度-长度:%{public}d", totalLength);
      let readerBuffer = new ArrayBuffer(1024 * 1024);
      let readLength: number = 0;
      let currentOffset: number = 0;
      let rawOffset = rawFile.offset;
      L.d("rawFileToLocal", "原始偏移量:%{public}d", rawOffset);
      while ((readLength =
        fileIo.readSync(rawFile.fd, readerBuffer,
          { offset: currentOffset + rawOffset, length: readerBuffer.byteLength })) > 0) {
        if (readLength > totalLength) {
          readLength = totalLength;
        }
        fileIo.writeSync(localFile.fd, readerBuffer.slice(0, readLength), {
          offset: currentOffset,
          length: readLength
        });
        currentOffset += readLength;
        L.d("rawFileToLocal", "循环读写文件-长度:%{public}d,结束后的偏移量:%{public}d", readLength, currentOffset);
        if (currentOffset >= totalLength) {
          break;
        }
      }
      if (fileIo.accessSync(localFilePath)) {
        let stat = fileIo.statSync(localFilePath);
        L.d("rawFileToLocal", "结束后的文件大小：%{public}d", stat.size);
        // if (stat.size >= totalLength) {
        //   return true;
        // }
      } else {
        L.e("rawFileToLocal", "复制完成后文件不存在");
      }
    } catch (e) {
    } finally {
      if (rawFile) {
        context.resourceManager.closeRawFdSync(assesFilePath);
      }
      if (localFile) {
        fileIo.closeSync(localFile);
      }
    }
    return false;
  }
}